/**
 * XQuery to Scala Translator
 * Fatemeh Borran-Dejnabadi
 * 15 December 2004
 */

package xquery2src;

/** This class is used to represent symbol tables.
 */
class Scope(val outer:Scope) {

  /** The first symbol in this scope; all other symbols are chained and
   *  can be accessed using the symbol's 'next' link.
   */
  var first:Symbol = null;

  /** Enters a symbol into the scope.
   */
  def enter(symbol:Symbol):Unit = {
    val other:Symbol = lookupLocal(symbol.name);
    if (other != null)
      Report.error(symbol.pos,
                   symbol.name + " is already defined at line " +
                   Position.line(other.pos));
    symbol.next = first;
    first = symbol;
  }

  /** Tries to find a symbol for the given name in the scope
   *  (including all outer scopes). If this method doesn't find
   *  one, it will return null.
   */
  def lookup(name:String):Symbol = {
    var scope:Scope = this;
    var symbol:Symbol = scope.lookupLocal(name);
    while (scope != null) {
      symbol = scope.lookupLocal(name);
      if (symbol != null)
        return symbol;
      scope = scope.outer;
    }
    return null;
  }

  /** Tries to find a symbol for the given name in the local
   *  scope only (including all outer scopes). 
   *  If this method doesn't find one, it will return null.
   */
  private def lookupLocal(name:String):Symbol = {
    var symbol:Symbol = first; 
    while (symbol != null) {
      if (symbol.name.equals(name))
        return symbol;
      symbol = symbol.next;
    }
    return null;
  }

  /** Returns a textual representation of this scope (and all outer*
   *  scopes).
   */
  override def toString():String = {
    var buffer:StringBuffer = new StringBuffer();
    buffer.append("{");
    var symbol:Symbol = first; 
    while (symbol != null) {
      if (symbol != first)
        buffer.append(", ");
      buffer.append(symbol);
      symbol = symbol.next;
    }
    if (outer != null) {
      if (first != null)
        buffer.append(", ");
      buffer.append(outer);
    }
    buffer.append("}");
    return buffer.toString();
  }
}
